<?php

namespace Gnway\Util\Concurrent;

/**
 * Class AbstractPool
 *
 * @author zushaolong
 * @mail zushaolong@gmail.com
 */
abstract class AbstractPool
{

  /**
   * The pool name
   *
   * @var string
   */
  protected string $name = '';

  /**
   * Process pool list
   *
   * @var Process[]
   */
  protected array $processes = [];

  /**
   * Submit a process to the pool
   *
   * @param Runnable $task
   * @return void
   */
  public function submit(Runnable $task): void
  {
    if (!($task instanceof Process)) {
      $task = new Process($task);
    }

    $this->processes[] = $task;
  }

  /**
   * Start the pool
   *
   * @return void
   */
  public function start(): void
  {
    $this->registerSignalHandler();

    if (!empty($this->name) && function_exists('cli_set_process_title')) {
      cli_set_process_title($this->name);
    }

    $this->scheduler();
  }

  /**
   * Register signal handler
   *
   * @return void
   */
  protected function registerSignalHandler(): void
  {
    pcntl_async_signals(TRUE);

    pcntl_signal(SIGTERM, function ($signal): void {
      $this->shutdown($signal);
    });
  }

  /**
   * Shutdown all processes in the process pool
   *
   * @param int $signal
   * @return void
   */
  abstract public function shutdown(int $signal = SIGTERM): void;

  /**
   * Waiting for all processes in the pool to exit
   *
   * @param int $timeout
   * @return void
   */
  abstract public function wait(int $timeout = 0): void;

  /**
   * Schedule all processes in the pool
   *
   * @return void
   */
  abstract protected function scheduler(): void;

  /**
   * Set pool name
   *
   * @param string $name
   * @return void
   */
  public function setName(string $name = ''): void
  {
    $this->name = trim($name);;
  }

  /**
   * Get the pool name
   *
   * @return string
   */
  public function getName(): string
  {
    return $this->name;
  }
}